/*
运算符重载，对已有的运算符重新进行定义，赋予其另一种功能，以适应不同的数据

加号运算符重载，实现两个自定义数据类型相加，对内置的数据类型的表达式的运算符是不可以改变的。不要乱用运算符重载。
有成员函数方式，全局函数方式，以及会发生函数重载。

左移运算符重载，可是输出自定义的数据类型
成员函数无法实现左移运算符重载

递增运算符重载，通过重载递增运算符，实现自己的整形数据
前置递增返回引用，后置递增返回值

赋值运算符重载
c++编译器至少给一个类添加4个函数
  默认构造函数(无参，函数体为空)
  默认析构函数(无参，函数体为空)
  默认拷贝构造函数，对属性进行值拷贝
  赋值运算符 operator=, 对属性进行值拷贝
如果类中有属性指向堆区，做赋值操作时也会出现深浅拷贝问题

关系运算符重载，可以让两个自定义类型的对象进行对比操做

函数调用运算符()重载，由于重载后使用的方式非常像函数调用，因此称为仿函数。仿函数没有固定的写法，非常灵活。
*/

#include <iostream>
using namespace std;

class Persion
{
public:
    Persion()
    {
        m_id = 0;
    }
    Persion(int a, int b)
    {
        this->m_a = a;
        this->m_b = b;
    }
    Persion(int a)
    {
        this->m_page = new int(a); // 将 p 开辟到堆区
    }

    // 成员函数实现 + 运算符重载
    Persion operator+(Persion &persion)
    {
        cout << "This is member func reload(+)..." << endl;
        Persion temp;
        temp.m_a = persion.m_a + this->m_a;
        temp.m_b = persion.m_b + this->m_b;
        return temp;
    }

    // 成员函数 实现不了  p << cout 不是我们想要的效果
    // void operator<<(Person& p){
    // }

    // 前置++ 先++ 在返回
    Persion& operator++()
    {
        // cout << "This is ++n..." << endl;
        m_id++;       // 先++
        return *this; // 再返回
    }

    // 后置++ 先返回 在++
    Persion operator++(int)
    {
        // cout << "This is n++..." << endl;
        Persion temp = *this; // 先记录修改前 （先返回）
        m_id++;               // 再++
        return temp;
    }

    // 赋值运算符重载
    Persion &operator=(Persion &p)
    {
        if (m_page != NULL)
        {
            delete m_page;
            m_page = NULL;
        }

        // 编译器默认提供的是浅拷贝
        // m_page = p.m_page;

        // 提供深拷贝 解决浅拷贝的问题
        m_page = new int(*p.m_page);

        m_a = p.m_a;
        m_b = p.m_b;

        // 返回自身
        return *this;
    }

    // 关系运算符重载
    bool operator==(Persion &p)
    {
        if (this->m_a == p.m_a && this->m_b == p.m_b)
            return true;
        else
            return false;
    }

public:
    int m_a;
    int m_b;
    int m_id;
    int *m_page;
};

// 全局函数实现运算符重载
// Persion operator+(Persion &p1, Persion &p2)
// {
//     Persion temp(0, 0);
//     temp.m_a = p1.m_a + p2.m_a;
//     temp.m_b = p1.m_b + p2.m_b;
// }

// 运算符重载可以发生函数重载
Persion operator+(Persion &p, int val)
{
    cout << "This is fun reload(+)..." << endl;
    Persion temp;
    temp.m_a = p.m_a + val;
    temp.m_b = p.m_b + val;
    return temp;
}

// 左移运算符重载
ostream &operator<<(ostream &out, Persion &p)
{
    cout << "<< oprtator reload..." << endl;
    out << "a: " << p.m_a << " b: " << p.m_b;
    return out;
}

class MyAdd
{
public:
    int operator()(int a, int b)
    {
        return a + b;
    }
};

int
main()
{
    // + 运算符重载
    Persion p1(10, 20);
    Persion p2(20, 30);

    // 调用成员函数方式
    Persion p3 = p1 + p2; // 相当于 p1.operator+(p2)
    cout << "p3.m_a = " << p3.m_a << endl;

    // 调用函数重载方式
    Persion p4 = p1 + 5; // 相当于 operator+(p1, 10)
    cout << "p4.m_a = " << p4.m_a << endl;

    // 左移运算符重载
    cout << p1 << " hello world" << endl; // 链式编程

    // 递增运算符重载
    Persion p5;
    cout << "current p5: " << p5.m_id << " ++p5: " << ++p5.m_id << endl;
    cout << "current p5: " << p5.m_id << " p5++: " << p5++.m_id << " p5: " << p5.m_id << endl;

    // 赋值运算符重载
    Persion p6(10);
    Persion p7 = p6;
    cout << "p6.m_page = " << *p6.m_page << " p7.m_page = " << *p7.m_page << endl;

    // 关系运算符重载
    cout << "p1.m_a = " << p1.m_a << " p1.m_b = " << p1.m_b << endl;
    cout << "p2.m_a = " << p2.m_a << " p2.m_b = " << p2.m_b << endl;
    if (p1 == p2)
        cout << "p1 == p2" << endl;
    else
        cout << "p1 != p2" << endl;

    // 函数调用运算符重载
    MyAdd add;
    int ret = add(1, 2);
    cout << "ret = " << ret << endl;

    //匿名对象调用  
	cout << "MyAdd()(100,100) = " << MyAdd()(100, 100) << endl;
  
    return 0;
}